
//HID 高频卡操作

#include <phApp_Init.h>
#include <phNfcLib_Int.h>
#include <phNfcLib_Initialization.h>
#include "Log.h"
#include "Reader.h"
#include "BSP.h"
#include <HID/exception.h>
#include <HID/tlv.h>
#include <HID/command.h>
#include <HID/HIDiClass.h>
#include <HID/ipcMessage.h>
#include <HID/HidRF.h>
#include <HID/asn1.h>
#include <HID/SIM.h>
#include <HID/HidSAM.h>
#include <HID/SeosAuthKeyDerivation/diversifyKAUTH.h>

int Reader_HID_HF_ExtractData(uint8_t * ptr, uint16_t objectLength, uint8_t tag, uint8_t* pdata, uint8_t* dlen){
	int e = 0;
	
	Try {
		uint16_t clen;
		clen = tlv_search(&ptr, &objectLength, tag);
		if(pdata){
			memcpy(pdata, ptr, clen);
		}
		if(dlen){
			*dlen = clen;
		}
	}
	Catch(e){
	
	}
	
	return e;
}

static int Reader_HID_HF_CheckCardType(void){
//TODO:考虑无卡情况
	switch(reader.curHfTag.type){
	case HFTAG_HIDICLASS:
		return 1;
	case HFTAG_MIFARE:
		return 2;
	case HFTAG_ISO14443B:
		return 3;
	}
	
	return 0;
}

int Reader_HID_HF_Init(void){
	SIM_Init();
	reader.hidState = 0;
	return 0;
}

int Reader_HID_HF_ResetRF(void){
	HID_RF_SetFeild(0);
	BSP_Sleep_Ms(6);
	HID_RF_SetFeild(1);
	return 0;
}

int Reader_HID_HF_CheckSE(void){
	int i;
	int ret;
	uint8_t atr[32];
	uint8_t alen;
	
	for(i = 0; i < 3; i++){
		ret = SIM_PowerOn(atr, &alen);
		if(!ret){
			return 1;
		}
		BSP_Sleep_Ms(10);
	}

	return 0;
}

int Reader_HID_HF_PowerOnSE(void){
	uint8_t atr[32];
	uint8_t alen;
	int ret = SIM_PowerOn(atr, &alen);
	return ret;
}

int Reader_HID_HF_GetECP(AppleWalletECParam_T* ecp){
	uint32_t tb_tci;
	uint8_t exp_tra;
	int ret = HID_SAM_QueryECP(&tb_tci, &exp_tra);
	if(ret){
		return ret;
	}
	ecp->tb_tci = tb_tci;
	switch(exp_tra){
	case 0x00: ecp->exr_tra = 0xC3; break;
	case 0x01: ecp->exr_tra = 0x83; break;
	default:
		LOG_E("Unknown exr_tra(%02X)", exp_tra);
		ecp->exr_tra = 0xC3;
		break;
	}
	return 0;
}

int Reader_HID_HF_SetupSE(void){
	int ret = -1;
	uint8_t *resp = NULL;
	uint8_t buf[64];
	uint8_t rlen = 0;
	
	HID_RF_SetDataFormatFlags(0, 0);
	
	if(PHAC_DISCLOOP_CHECK_ANDMASK(reader.wTagsDetected, PHAC_DISCLOOP_POS_BIT_MASK_A))
	{
		phacDiscLoop_Sw_DataParams_t *pDataParams = reader.pDiscLoop;
		uint8_t* uid = pDataParams->sTypeATargetInfo.aTypeA_I3P3[0].aUid;
		uint8_t ulen = pDataParams->sTypeATargetInfo.aTypeA_I3P3[0].bUidSize;
		uint8_t sak = pDataParams->sTypeATargetInfo.aTypeA_I3P3[0].aSak;
		uint8_t *ats = pDataParams->sTypeATargetInfo.sTypeA_I3P4.pAts;
		uint8_t tcl = 1;
		uint8_t alen = ats[0];
		
		if((sak & 0x20) == 0){
			alen = 0;
			tcl = 0;
		}
		else{
			alen--;
		}
		HID_RF_TransceiveSelect(tcl);
		//Do not include the ATS TL byte
		ret = SamCommand_SetDetectedCardInfo2(ASN1_FRAME_PROTOCOL_ISO14443A, uid, ulen, ats + 1, alen, &sak, NULL, &resp, &rlen);
		if(ret){
			LOG_E("SamCommand_SetDetectedCardInfo2 (%d), fail: %d", ASN1_FRAME_PROTOCOL_ISO14443A, ret);
		}
	}
	else
	if(PHAC_DISCLOOP_CHECK_ANDMASK(reader.wTagsDetected, PHAC_DISCLOOP_POS_BIT_MASK_B))
	{
		//TODO: HID的B卡未测试
		phacDiscLoop_Sw_DataParams_t *pDataParams = reader.pDiscLoop;
		uint8_t* atqb = pDataParams->sTypeBTargetInfo.aTypeB_I3P3[0].aAtqB;
		uint8_t alen = pDataParams->sTypeBTargetInfo.aTypeB_I3P3[0].bAtqBLength;
		uint8_t* uid = pDataParams->sTypeBTargetInfo.aTypeB_I3P3[0].aPupi;
		uint8_t ulen = 4;
		HID_RF_TransceiveSelect(1);
		ret = SamCommand_SetDetectedCardInfo2(ASN1_FRAME_PROTOCOL_PICO14443B, uid, ulen, atqb, alen, NULL, NULL, &resp, &rlen);
		if(ret){
			LOG_E("SamCommand_SetDetectedCardInfo2 (%d), fail: %d", ASN1_FRAME_PROTOCOL_PICO14443B, ret);
		}
	}
	else
	if(reader.curHfTag.type == HFTAG_HIDICLASS){
		HID_RF_TransceiveSelect(0);
		ret = SamCommand_PerformAnticollision(ASN1_FRAME_PROTOCOL_PICO15693, buf, &rlen);
		if(ret){
			LOG_E("SamCommand_PerformAnticollision fail: %d", ret);
		}
	}
	return 0;
}


int Reader_HID_HF_GetPACBits(uint8_t pac[], uint8_t *len){
	int ret = Reader_HID_HF_CheckCardType();
	//检查卡类型
	if(!ret){
		LOG_E("card type not support!");
		return -1;
	}
	//SE模块上电
	ret = Reader_HID_HF_PowerOnSE();
	if(ret){
		LOG_E("PowerOnSE fail: %d", ret);
		return ret;
	}
	//把卡信息发给SE
	ret = Reader_HID_HF_SetupSE();
	if(ret){
		LOG_E("SetupSE fail: %d", ret);
		return ret;
	}
	//获取卡片PAC
	
	uint8_t* resp = NULL;
	uint8_t rlen = 0;
	ret = SamCommand_GetContentElement2(&resp, &rlen);
	if(ret){
		LOG_E("SamCommand_GetContentElement2 fail: %d", ret);
		return ret;
	}
	//提取数据
	const uint8_t tag = ASN1_CHOICE_PRIMITIVE|0;
	ret = Reader_HID_HF_ExtractData(resp, rlen, tag, pac, len);
	if(ret){
		LOG_E("IClass_ExtractData: %d", ret);
		return ret;
	}

	return 0;
}


int Reader_HID_HF_IsJCOP(const uint8_t *ats){
	uint8_t TL = ats[0];
	uint8_t T0, TA, TB, TC;
	uint8_t len = 1;
	if(TL < 2){
		return 0;
	}
	T0 = ats[len++];
	if (T0 & 0x10) {
		TA = ats[len++];
	}
	if (T0 & 0x20) {
		TB = ats[len++];
	}
	if (T0 & 0x40) {
		TC = ats[len++];
	}
	(void)TA;(void)TB;(void)TC;
	if(len >= TL){
		return 0;
	}
	uint8_t hlen = TL - len;
	if(hlen < 4){
		return 0;
	}
	
	if(memcmp(&ats[len], "JCOP", 4) != 0){
		return 0;
	}

	return 1;
}


static int Reader_HID_HF_CheckJCOP(void){

	if(!PHAC_DISCLOOP_CHECK_ANDMASK(reader.wTagsDetected, PHAC_DISCLOOP_POS_BIT_MASK_A)){
		LOG_E("Not TypeA card");
		return 0;
	}
	phacDiscLoop_Sw_DataParams_t *pDataParams = reader.pDiscLoop;
	uint8_t sak = pDataParams->sTypeATargetInfo.aTypeA_I3P3[0].aSak;
	uint8_t *ats = pDataParams->sTypeATargetInfo.sTypeA_I3P4.pAts;
	if((sak & 0x20) == 0){
		LOG_E("Not CPU card");
		return 0;
	}
	
	if(!Reader_HID_HF_IsJCOP(ats)){
		LOG_E("Not JCOP card");
		return 0;
	}

	return 1;
}

int Reader_HID_HF_ProcessAdminKey(void){
	int ret = Reader_HID_HF_CheckJCOP();
	//检查卡类型
	if(!ret){
		return -1;
	}
	//SE模块上电
	ret = Reader_HID_HF_PowerOnSE();
	if(ret){
		LOG_E("PowerOnSE fail: %d", ret);
		return ret;
	}
	//把卡信息发给SE
	ret = Reader_HID_HF_SetupSE();
	if(ret){
		LOG_E("SetupSE fail: %d", ret);
		return ret;
	}
	//处理密钥卡
	return SamCommand_ProcessKeyRollerCard();
}

int Reader_HID_HF_ProcessConfigCard(void){
	int ret = Reader_HID_HF_CheckJCOP();
	//检查卡类型
	if(!ret){
		return -1;
	}
	//SE模块上电
	ret = Reader_HID_HF_PowerOnSE();
	if(ret){
		LOG_E("PowerOnSE fail: %d", ret);
		return ret;
	}
	//把卡信息发给SE
	ret = Reader_HID_HF_SetupSE();
	if(ret){
		LOG_E("SetupSE fail: %d", ret);
		return ret;
	}
	//处理配置卡
	return SamCommand_ProcessConfigCard();
}

int Reader_HID_HF_CheckSeosCardType(void){
	const uint8_t aidSeos[] = {0xA0, 0x00, 0x00, 0x04, 0x40, 0x00, 0x01, 0x01, 0x00, 0x01};
	const uint8_t aidConfig[] = {0xA0, 0x00, 0x00, 0x03, 0x82, 0x00, 0x13, 0x00, 0x01, 0x01};
	const uint8_t aidAdmin[] = {0xA0, 0x00, 0x00, 0x03, 0x82, 0x00, 0x17, 0x00, 0x01, 0x01};
 	void * hal = phNfcLib_GetDataParams(PH_COMP_HAL);
	uint16_t t;
//		phhalHw_SetConfig(hal, PHHAL_HW_CONFIG_TIMEOUT_VALUE_MS, 100);
	phhalHw_GetConfig(hal, PHHAL_HW_CONFIG_TIMEOUT_VALUE_MS, &t);
	TRACE_D("timeout=%d ms", t);
	if(!HID_RF_SelectSeosCard(aidSeos, sizeof(aidSeos))){
		//Seos
		return 1;
	}
	
	if(!Reader_HID_HF_CheckJCOP()){
		//未知
		return 0;
	}
	
	if(!HID_RF_SelectSeosCard(aidConfig, sizeof(aidConfig))){
		//Config
		return 2;
	}
	
	if(!HID_RF_SelectSeosCard(aidAdmin, sizeof(aidAdmin))){
		//Admin
		return 3;
	}
	//未知
	return 0;
}

#if 0
int Reader_HID_HF_DoECP(void){
#if 1
	if(reader.ecp.tb_tci != 0u){
		return HID_RF_DoECP(reader.ecp.exr_tra, reader.ecp.tb_tci);
	}
#endif 
	return -1;
}

#else	
int Reader_HID_HF_DoECP(void){
//6a  02  c3  02  02  02  09  01  8a  c0
	uint32_t tb_tci;
	uint8_t tci[] = {0x02, 0x02, 0x09, 0x01};
	memcpy(&tb_tci, tci, sizeof(tci));
	return HID_RF_DoECP(0xC3, tb_tci);
}
#endif 

/*--------------------------------------------------------------------------------------------------*/
//Seos
/*--------------------------------------------------------------------------------------------------*/

#define SEOS_CHECK_RETURN(act)	do{int _r; if((_r = (act)) != 0){LOG_E(#act ": %d", _r); return _r;}}while(0)

int Reader_HID_Seos_Select(uint8_t* fci, uint8_t* fciLen){
	//SE模块上电
	SEOS_CHECK_RETURN(Reader_HID_HF_PowerOnSE());
	//把卡信息发给SE
	SEOS_CHECK_RETURN(Reader_HID_HF_SetupSE());
	uint8_t* resp;
	uint16_t rlen;
	SEOS_CHECK_RETURN(SamCommand_Seos_Select2(&resp, &rlen));
	uint8_t ilen = 0;
	SEOS_CHECK_RETURN(SamCommand_ExtractData(resp, rlen, 0x8A, fci, fciLen));
	return 0;
}

int Reader_HID_Seos_Authenticate(const uint8_t adf[], uint8_t adfLen, 
		const uint8_t privEncKeyOid[3], const uint8_t privMacKeyOid[3], const uint8_t authKeyOid[3]){
	return SamCommand_Seos_Authenticate(adf, adfLen, privEncKeyOid, privMacKeyOid, authKeyOid);
}

int Reader_HID_Seos_GetData(uint8_t tagLen, const uint8_t* tag, uint8_t readLen, uint8_t* readData, uint8_t* ilen){
	uint8_t * resp;
	uint16_t rlen;
	SEOS_CHECK_RETURN(SamCommand_Seos_GetData(tag, tagLen, readLen, &resp, &rlen));
	SEOS_CHECK_RETURN(SamCommand_ExtractData(resp, rlen, 0x8A, readData, ilen));
	return 0;
}

int Reader_HID_Seos_PutData(uint8_t tagLen, const uint8_t* tag, uint8_t writeLen, const uint8_t* writeData){
	SEOS_CHECK_RETURN(SamCommand_Seos_PutData(tag, tagLen, writeLen, writeData));
	return 0;
}

enum AlgoID{
	DES2K = 2,
	DES3K = 4,
	SHA1 = 6,
	SHA256 = 7,
	AES128 = 9
};

int Reader_HID_Seos_GatherCardInfo(uint8_t* diversifier, uint8_t* diversifierLength, uint8_t* cipher, uint8_t* hash){
	uint8_t * resp;
	uint16_t rlen;
	uint8_t ilen = 0;
	SEOS_CHECK_RETURN(SamCommand_Seos_GetLastDiversifier(&resp, &rlen));
	SEOS_CHECK_RETURN(SamCommand_ExtractData(resp, rlen, 0x8A, diversifier, diversifierLength));
	//The last byte is always 0xED
	if(diversifier[*diversifierLength - 1] != 0xED){
		return -3;
	}
	SEOS_CHECK_RETURN(SamCommand_Seos_GetAlgoInfo(&resp, &rlen));
	uint8_t data[32];
	uint8_t dlen;
	SEOS_CHECK_RETURN(SamCommand_ExtractData(resp, rlen, 0x8A, data, &dlen));
	if(data[0] != 0x30 || data[1] != 0x06){
		return -2;
	}
	SEOS_CHECK_RETURN(SamCommand_ExtractData(data+2, dlen-1, 0x80, cipher, &ilen));
	SEOS_CHECK_RETURN(SamCommand_ExtractData(data+2, dlen-1, 0x81, hash, &ilen));
	return 0;
}

int Reader_HID_Seos_WritePrivacyKey(uint8_t cipher, const uint8_t* encKey, uint8_t elen, const uint8_t* macKey, uint8_t mlen){
	if(cipher != DES2K && cipher != AES128){
		TRACE_E("Not support cipher(%d)", cipher);
		return -1;
	}
	if(elen != 16 || mlen != 16){
		TRACE_E("key len error: elen(%d), mlen(%d)", elen, mlen);
		return -2;
	}
	const uint8_t keyTag[2] = {0xDF,0x70};
	uint8_t keyData[0x31] = {
		0x85,
		0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
		0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
	};
	/*
	CMAC_subkey_K2 length equals cipher algo block size
	l 2K3DES (8x '00' bytes)
	l AES-128 (16x '00' bytes)
	*/
	memcpy(&keyData[1], encKey, elen);
	memcpy(&keyData[1+elen], macKey, mlen);
	uint8_t len = sizeof(keyData);
	if(cipher == DES2K){
		len -= 8;
	}
	return SamCommand_Seos_PutData(keyTag, sizeof(keyTag), len, keyData);
}

int Reader_HID_Seos_ChangeAuthKey(uint8_t auth[16], const uint8_t* adf, uint8_t alen, 
	const uint8_t* diversifier, uint8_t diversifierLength, uint8_t cipher, uint8_t hash){
	
	uint8_t keyNumber = 1;
	uint8_t divKeyLength = 16;
	uint8_t divKENC[16];
	uint8_t divKMAC[16];
	
	if(cipher != AES128 && cipher != DES2K){
		TRACE_E("Not support cipher(%d)", cipher);
		return -1;
	}
	
	if(hash != SHA1 && hash != SHA256){
		TRACE_E("Not support hash(%d)", hash);
		return -1;
	}
	
	if(diversifierLength != 5 || diversifier[4] != 0xED){
		TRACE_E("Invalid diversifier：diversifierLength = %d, diversifier[4]=%d", diversifierLength, diversifier[4]);
		return -2;
	}

	//分散密钥
	diversifyKAUTH(auth, (uint8_t*)adf, alen, (uint8_t*)diversifier, diversifierLength, cipher, hash, keyNumber, divKENC, divKMAC, divKeyLength);
	LOG_SBUF("Diversifier", diversifier, diversifierLength);
	LOG_SBUF("adf", adf, sizeof(adf));
	LOG_SBUF("authKey", auth, 16);
	LOG_SBUF("divKENC", divKENC, divKeyLength);
	LOG_SBUF("divKMAC", divKMAC, divKeyLength);
	const uint8_t authTag[2] = {0xDF,0x71};
	uint8_t authData[0x35] = {
		0x9C,0x01,
		0x00,0x00,0x00,
		0x67,0x6B,0x1E,0x41,0xAC,0xE4,0xB4,0xA4,0xE9,0x53,0xCC, 	0x55,0xAF,0x15,0xE0,0x6B,
		0x21,0xD0,0xC0,0x18,0x46,0x08,0xB9,0x98,0x6B,0x2B,0xA2, 	0xAF,0xD7,0xED,0x14,0x15,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 	0x00,0x00,0x00,0x00,0x00
	};
	memcpy(&authData[5], divKENC, divKeyLength);
	memcpy(&authData[5+divKeyLength], divKMAC, divKeyLength);
	uint8_t len = sizeof(authData);
	if(cipher == DES2K){
		len -= 8;
	}

	return SamCommand_Seos_PutData(authTag, sizeof(authTag), len, authData);
}


